package factory

import (
	"apibe/grpc/rome/v1/factory/tools"
	"apibe/grpc/rome/v1/share/rpc"
	"context"
	"errors"
	"fmt"
	"net/http"
	"strings"
	"time"
)

// 组装师傅按照图纸把接口组装起来并试图请求

func (d *Design) AutoAssembly(catch map[string]string, timeOut time.Duration) ([]byte, int, bool, error) {
	//fmt.Println(1)
	req := &rpc.RoadsRequest{}
	req.Header = make(map[string]string) // 初始化map
	err := d.valueReplace(catch)
	if err != nil {
		return nil, http.StatusBadRequest, false, err
	}
	d.assemblyCache()
	// 尝试取缓存
	if bytes, err := d.Cache.CacheGet(); err == nil {
		return bytes, http.StatusOK, true, err
	}
	d.doArgumentFunction()
	//fmt.Println(2)
	d.assemblyUrl(req)
	//fmt.Println(3)
	d.assemblyMethod(req)
	//fmt.Println(4)
	d.assemblyHeader(req)
	//fmt.Println(5)
	d.assemblyContentType(req)
	//fmt.Println(6)
	d.assemblyRequestBody(req)
	//fmt.Println(7)
	//if d.RequestFunction.FunctionName != "" {
	//	d.doRequestFunction(req)
	//}
	//res, err := req.SentHttp(timeOut)
	//if err != nil {
	//	if res != nil {
	//		return nil, res.Status, false, err
	//	} else {
	//		return nil, http.StatusBadGateway, false, err
	//	}
	//}
	//if d.ResponseFunction.FunctionName != "" {
	//	d.doResponseFunction(res)
	//}
	res, err := d.roads(req)
	d.doFormat(res) // 会进行存缓存
	fmt.Println(string(res.Body))
	return res.Body, int(res.Status), false, err
}

// 把请求体内容和数据库数据相组合
func (d *Design) valueReplace(catch map[string]string) error {
	for key, value := range catch {
		for i, argument := range d.Data.Argument {
			if key == argument.Key && argument.ArgumentOpinion != tools.Static {
				d.Data.Argument[i].Value = value
			}
			////fmt.println(argument.Key, argument.Value)
			if argument.ArgumentOpinion == tools.Required && catch[argument.Key] == "" {
				err := fmt.Sprintf("key %v is required", argument.Key)
				return errors.New(err)
			}
		}
	}
	return nil
}

// 把缓存的key值组装好
// NewKey
// 获取一个新的缓存id
func (d *Design) assemblyCache() {
	key := d.ApiName + "-" + d.Cache.Key
	for _, arg := range d.Data.Argument {
		key = strings.Replace(key, "$."+arg.Key, arg.Value, -1)
	}
	//fmt.println("key", key)
	d.Cache.Key = key
}

// 1. 执行 argument-function
func (d *Design) doArgumentFunction() {
	////fmt.println("argument长度", len(d.Data.Argument))
	for i, argument := range d.Data.Argument {
		if argument.Function.FunctionName != "" {
			////fmt.println("遍历次数", i)
			d.Data.Argument[i].Tools()
		}
	}
}

// 2. 拼装 url
func (d *Design) assemblyUrl(req *rpc.RoadsRequest) {
	uri := d.Data.Url
	// 1. 拼接需要添加的 url 后半部分
	path := d.Data.Argument.GetValuesEncode(tools.Param)
	// 2. 组装 url param
	if path != "" {
		if !strings.Contains(d.Data.Url, "?") {
			uri = fmt.Sprint(d.Data.Url, "?", path)
		} else {
			uri = fmt.Sprint(d.Data.Url, path)
		}
	}
	// 3. 组装 url pathValue
	for _, argument := range d.Data.Argument {
		if argument.ArgumentType == tools.PathVariables {
			uri = strings.Replace(uri, fmt.Sprintf("{%v}", argument.Key), argument.Value, 1)
		}
	}
	d.Data.Url = uri
	req.Url = uri
}

// 3. 拼装 method
func (d *Design) assemblyMethod(req *rpc.RoadsRequest) {
	if d.Data.Method != "" {
		req.Method = d.Data.Method
	}
}

// 4. 拼装 content-type
func (d *Design) assemblyContentType(req *rpc.RoadsRequest) {
	if d.Data.ContentType != "" {
		req.Header["Content-Type"] = d.Data.ContentType
	}
}

// 5. 拼装 header
func (d *Design) assemblyHeader(req *rpc.RoadsRequest) {
	reqHeader := make(map[string]string)
	arguments := d.Data.Argument
	for _, arg := range arguments {
		if arg.ArgumentType == tools.Header || arg.ArgumentType == tools.Auto {
			reqHeader[arg.Key] = arg.Value
		}
	}
	req.Header = reqHeader
}

// 6. 拼装 request body
func (d *Design) assemblyRequestBody(req *rpc.RoadsRequest) {
	switch d.Data.ContentType {
	case None:
		reqBody := []byte(d.Data.Argument.GetValuesEncode(tools.Body))
		d.Data.Body = string(reqBody)
		req.Body = reqBody
		break
	case ApplicationJson:
		str := d.Data.Body
		for _, argument := range d.Data.Argument {
			value := strings.TrimSpace(argument.Value)
			if argument.ArgumentType == tools.Body || argument.ArgumentType == tools.Auto {
				str = strings.Replace(str, "$."+argument.Key, value, -1)
			}
		}
		//fmt.println(str)
		d.Data.Body = str
		req.Body = []byte(str)
		break
	case ApplicationXForm:
		reqBody := []byte(d.Data.Argument.GetValuesEncode(tools.Body))
		d.Data.Body = string(reqBody)
		req.Body = reqBody
		break
	case ApplicationXml:
		str := d.Data.Body
		for _, argument := range d.Data.Argument {
			if argument.ArgumentType == tools.Body {
				str = strings.Replace(str, "$."+argument.Key, argument.Value, -1)
			}
		}
		d.Data.Body = str
		req.Body = []byte(str)
		break
	default:
		reqBody := []byte(d.Data.Argument.GetValuesEncode(tools.Body))
		d.Data.Body = string(reqBody)
		req.Body = reqBody
		break
	}
}

// 7. 执行 reqFunc&resFunc
func (d *Design) roads(req *rpc.RoadsRequest) (*rpc.RoadsResponse, error) {
	client, err := rpc.GetRoadsClient()
	if err != nil {
		return nil, err
	}
	reqFunc := rpc.ReqFunction{Name: d.RequestFunction.FunctionName, Parameter: []byte(d.RequestFunction.Parameter)}
	resFunc := rpc.ResFunction{Name: d.ResponseFunction.FunctionName, Parameter: []byte(d.ResponseFunction.Parameter)}
	req.ReqFunction = &reqFunc
	req.ResFunction = &resFunc
	fmt.Println(req)
	res, err := client.AOP(context.Background(), req)
	if err != nil {
		fmt.Println("err：", err.Error())
	}
	fmt.Println(res)
	return res, nil
}

// 8. 执行 最终格式化
func (d *Design) doFormat(res *rpc.RoadsResponse) {
	if res.Status != http.StatusOK {
		return
	} else {
		res.Body = d.Format.Format(d.Cache, res.Body)
	}
}
